package com.authine.cloudpivot.ext.service.trade.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapBuilder;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.data.support.PageImpl;
import com.authine.cloudpivot.ext.Enum.TradeInvoiceStatus;
import com.authine.cloudpivot.ext.Enum.TradeSettleStatus;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.dto.base.PageList;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceApply;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceDetail;
import com.authine.cloudpivot.ext.dto.model.trade.Trade;
import com.authine.cloudpivot.ext.dto.query.TradeQuery;
import com.authine.cloudpivot.ext.service.trade.TradeService;
import com.authine.cloudpivot.ext.utils.BoServiceUtils;
import com.authine.cloudpivot.ext.utils.JdbcTemplateUtils;
import com.authine.mvp.app.launcher.dto.bo.response.BOList;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Maps;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class TradeServiceImpl implements TradeService {
    @Override
    public Trade loadById(String id) {
        return JdbcTemplateUtils.builder(ModelConst.T_TRADE).selectField("*").eq("id", id).queryForPOJO(Trade.class);
    }

    @Override
    public List<Trade> loadListByIds(List<String> ids) {
        return JdbcTemplateUtils.builder(ModelConst.T_TRADE).selectField("*").in("id", ids).queryForPOJOList(Trade.class);
    }

    @Override
    public PageList<Trade> listTradeByParam(TradeQuery query) {
        Map<String, Object> param = BeanUtil.beanToMap(query);
        StringBuffer  dataSql = new StringBuffer("select * from "+ JdbcTemplateUtils.getTableName(ModelConst.T_TRADE));
        dataSql.append(query.getWhereSql(param));
        String countSql = "select count(1) from (" + dataSql + ") as trade";
        Integer count = jdbcTemplate.queryForObject(countSql, param,Integer.class);
        PageList<Trade> pageList = new PageList();
        if(count==0){
            pageList.setTotal(0);
            return pageList;
        }
        String limit = String.format(" limit %s,%s", (query.getPageIndex() - 1) * query.getPageSize(), query.getPageSize());
        dataSql.append(" order by createdTime desc ").append(limit);
        log.info("dataSql = {}, parameters = {}", dataSql, JSONObject.toJSONString(param));
        List<Trade> tradeList = JdbcTemplateUtils.queryForPOJOList(dataSql.toString(), param, ModelConst.T_TRADE,Trade.class);
        pageList.setTotal(count);
        pageList.setData(tradeList);
        return pageList;
    }

    @Override
    public void writeBackAllowedInvoiceQuantity(List<String> tradeIds) {
        if (CollectionUtils.isEmpty(tradeIds)) {
            return;
        }
        StringBuffer sql = new StringBuffer("SELECT trade.ID tradeId, IFNULL(trade.price,0) tradePrice, ")
                .append(" IFNULL(trade.quantity,0) tradeQuantity, IFNULL(trade.total,0) tradeTotal, ")
                .append(" IFNULL(trade.allowed_invoice_quantity,0) allowedInvoiceQuantity, IFNULL(goods_bill.quantity,0) goodsQuantity, ")
                .append(" IFNULL(goods_bill.total,0) goodsTotal, IFNULL(refund_bill.quantity,0) refundQuantity, ")
                .append(" IFNULL(refund_bill.offset_quantity,0) refundOffsetQuantity, IFNULL(refund_bill.total,0) refundTotal, ")
                .append(" IFNULL(invoice_detail_bill.quantity,0) invoiceBillQuantity, IFNULL(invoice_detail_bill.total,0) invoiceBillTotal, ")
                .append(" invoice_detail_bill.invoice_ids invoiceIds, IFNULL(invoice_detail.quantity,0) invoiceQuantity  ")
                .append(" FROM i_financialcenter_t_trade trade  ")
                .append(" LEFT JOIN  ")
                .append("     (SELECT SUM(goods.total) total,SUM(goods.quantity) quantity,goods.trade_id trade_id")
                .append("     FROM i_financialcenter_t_bill goods WHERE goods.deleted = 0 AND goods.TYPE = 'Goods' GROUP BY goods.trade_id ) goods_bill ")
                .append(" ON goods_bill.trade_id = trade.ID ")
                .append(" LEFT JOIN ")
                .append("     (SELECT SUM(refund_bill.total) total,SUM(refund_bill.quantity) quantity,SUM(refund_bill.offset_quantity) offset_quantity,refund_bill.trade_id trade_id ")
                .append("     FROM i_financialcenter_t_bill refund_bill WHERE refund_bill.deleted = 0 AND refund_bill.TYPE = 'Refund' GROUP BY refund_bill.trade_id ) refund_bill ")
                .append(" ON refund_bill.trade_id = trade.ID  ")
                .append(" LEFT JOIN ")
                .append("     (SELECT SUM(invoice_detail_bill.total) total, SUM(invoice_detail_bill.quantity) quantity,invoice_detail_bill.trade_id trade_id, ")
                .append("        GROUP_CONCAT(DISTINCT invoice_detail_bill.invoice_apply_id) invoice_ids ")
                .append("      FROM i_financialcenter_t_invoice_detail_bill invoice_detail_bill ")
                .append("      LEFT JOIN ")
                .append("         i_financialcenter_t_invoice_apply apply ON apply.ID = invoice_detail_bill.invoice_apply_id ")
                .append("      WHERE apply.deleted = 0  AND apply.business_type = 'Product'  AND invoice_detail_bill.offset_quantity = 0   ")
                .append("            AND apply.statuss IN ( 'New', 'Approving', 'Returned', 'DrawerConfirming', 'ReceiverConfirming', 'Done' )  ")
                .append("            AND invoice_detail_bill.deleted = 0 AND invoice_detail_bill.bill_type = 'Goods'   ")
                .append("      GROUP BY invoice_detail_bill.trade_id) invoice_detail_bill   ")
                .append(" ON invoice_detail_bill.trade_id = trade.ID")
                .append(" LEFT JOIN ")
                .append("       (SELECT SUM(invoice_detail.quantity) quantity,invoice_detail.trade_id trade_id  ")
                .append("       FROM i_financialcenter_t_invoice_detail invoice_detail ")
                .append("       LEFT JOIN ")
                .append("            i_financialcenter_t_invoice_apply apply ON apply.ID = invoice_detail.invoice_apply_id ")
                .append("       WHERE apply.deleted = 0  AND apply.business_type = 'Product'  AND invoice_detail.offset_quantity = 0  AND apply.statuss='Done' AND invoice_detail.deleted = 0  ")
                .append("       GROUP BY invoice_detail.trade_id) invoice_detail ON invoice_detail.trade_id = trade.ID  ")
                .append(" where trade.id in(:tradeIds) ");
        List<Map<String, Object>> writeBackInvoiceList = JdbcTemplateUtils.queryForList(sql.toString(), Maps.newHashMap("tradeIds", tradeIds));
        //已申票数量和金额
        sql = new StringBuffer("select d.trade_id, SUM(d.quantity-d.offset_quantity) as quantity,SUM(d.total-d.offset_total) as total  ")
                .append(" from i_financialcenter_t_invoice_detail d LEFT JOIN i_financialcenter_t_invoice_apply a on d.invoice_apply_id = a.id")
                .append(" where d.deleted=0 and d.trade_id in (:tradeIds) ")
                .append(" and a.business_type = 'Product'")
                .append(" group by  d.trade_id");
        List<InvoiceDetail> alreadyInvoice = JdbcTemplateUtils.queryForPOJOList(sql.toString(), Maps.newHashMap("tradeIds", tradeIds), ModelConst.T_INVOICE_DETAIL, InvoiceDetail.class);

        if (CollectionUtils.isEmpty(writeBackInvoiceList)) {
            return;
        }
        List<Map<String, Object>> paramList = new ArrayList<>();
        for (Map<String,Object> map : writeBackInvoiceList){
            //可申请开票数量
            BigDecimal allowedQuantity = (BigDecimal) map.get("goodsQuantity");
            //可申请开票金额
            BigDecimal allowedTotal = (BigDecimal) map.get("goodsTotal");

            //退货账单总个数
            BigDecimal refundQuantity = (BigDecimal) map.get("refundQuantity");
            //退货个数，参与计算有效交易用
            BigDecimal tradeRefundQuantity = (BigDecimal) map.get("refundQuantity");
            BigDecimal refundTotalInvoice = (BigDecimal) map.get("refundTotal");
            BigDecimal refundTotal =  (BigDecimal) map.get("refundTotal");

            //退货账单的offset_quantity总个数（退货账单，退未收货的数量）
            BigDecimal refundOffsetQuantity =  (BigDecimal) map.get("refundOffsetQuantity");

            BigDecimal tradePrice = (BigDecimal) map.get("tradePrice");
            if(refundOffsetQuantity.compareTo(BigDecimal.ZERO) == 1){
                refundQuantity = refundQuantity.subtract(refundOffsetQuantity);
                refundTotalInvoice = refundQuantity.multiply(tradePrice).setScale(6, RoundingMode.HALF_UP);
            }
            if(refundQuantity.compareTo(BigDecimal.ZERO) == 1){
                if(refundQuantity.compareTo(allowedQuantity) == 1){
                    allowedQuantity = BigDecimal.ZERO;
                    allowedTotal = BigDecimal.ZERO;
                }else {
                    allowedQuantity = allowedQuantity.subtract(refundQuantity).setScale(6, RoundingMode.HALF_UP);
                    allowedTotal = allowedTotal.subtract(refundTotalInvoice).setScale(6, RoundingMode.HALF_UP);
                }
            }
            //发票明细账单的数量
            BigDecimal invoiceBillQuantity = (BigDecimal) map.get("invoiceBillQuantity");
            //发票明细账单的金额
            BigDecimal invoiceBillTotal = (BigDecimal) map.get("invoiceBillTotal");
            //发票明细的数量
            BigDecimal doneQuantity = (BigDecimal) map.get("invoiceQuantity");
            TradeInvoiceStatus invoiceStatus = TradeInvoiceStatus.Doing;
            //有效交易=交易数量-退的数量
            BigDecimal tradeQuantity = ((BigDecimal)map.get("tradeQuantity")).subtract(tradeRefundQuantity).setScale(6, RoundingMode.HALF_UP);

            if (doneQuantity.compareTo(tradeQuantity) >= 0) {
                //已开票
                invoiceStatus = TradeInvoiceStatus.Done;
            } else if (invoiceBillQuantity.compareTo(BigDecimal.ZERO) == 0) {
                //未申请
                invoiceStatus = TradeInvoiceStatus.Undo;
            }

            allowedQuantity = allowedQuantity.subtract(invoiceBillQuantity);
            allowedTotal = allowedTotal.subtract(invoiceBillTotal);
            if(allowedTotal.compareTo(BigDecimal.ZERO)==1 && allowedQuantity.compareTo(BigDecimal.ZERO) == 0){
                allowedQuantity = allowedTotal.divide(tradePrice).setScale(3,RoundingMode.HALF_UP);
            }
            log.info("交易ID：{}发票修改之前可申请数量{}，更改后数量{}，", map.get("tradeId"), map.get("allowedInvoiceQuantity"),allowedQuantity);
            String tradeId = map.get("tradeId").toString();
            InvoiceDetail detail = alreadyInvoice.stream().filter(t->t.getTrade_id().equals(tradeId)).findAny().orElse(new InvoiceDetail());
            Map<String, Object> param = new HashMap<>();
            param.put("id", tradeId);
            param.put("invoice_status", invoiceStatus.name());
            param.put("invoice_ids", map.get("invoiceIds"));
            param.put("allowed_invoice_quantity", allowedQuantity);
            param.put("allowed_invoice_total", allowedTotal);
            param.put("refund", refundTotal);
            param.put("already_invoice_quantity", detail.getQuantity());
            param.put("already_invoice_total", detail.getTotal());
            paramList.add(param);
        }
        if(paramList.size()>0){
            BoServiceUtils.updateMainBo(ModelConst.T_TRADE, paramList);
        }
    }

    @Override
    public boolean isRepayment(String orderGoodsId, String direction) {
        Trade trade = JdbcTemplateUtils.builder(ModelConst.T_TRADE).selectField("*")
                .eq("order_goods_id", orderGoodsId)
                .eq("direction", direction)
                .queryForPOJO(Trade.class);
        Assert.notNull(trade, "根据订单商品ID和交易方向获取交易异常");
        return TradeSettleStatus.Done.name().equals(trade.getSettle_status());
    }
}
